﻿using System;
using System.Collections.Generic;
using WickedFlame.Core;
using WickedFlame.Core.Shapes;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using WickedFlame.Util.Data;
using System.Linq;

namespace WickedFlame.Util.Actions
{
    /// <summary>
    /// If a selected region is to becopied then this class creates an image of the region and copies it to the clipboard
    /// else this class copies all the selected shapes to the clipboard.
    /// In adition this class creates an image of the selection with a white background for other applications to use
    /// </summary>
    public class CopyToClipboardAction
    {
        public void DoAction(DrawingCanvas canvas, Rect rectangle)
        {
            var shapes = new List<VectorShape>();
            var copiedShapes = new List<VectorShape>();

            foreach (VectorShape shape in canvas.SelectedLayer.ShapeList)
            {
                if (shape is ICopyable)
                    if (rectangle.Width > 0 && rectangle.Height > 0)
                    {
                        if (shape.IntersectsWith(rectangle))
                            shapes.Add(shape);
                    }
                    else
                        if (shape.IsSelected)
                            shapes.Add(shape);
            }

            foreach (var shape in shapes)
            {
                var s = ((ICopyable)shape).Copy();
                if (s != null)
                    copiedShapes.Add(s);
            }

			if (shapes.Count <= 0)
				return;

			if (rectangle.Width > 0)
			{
				// the rectangle is biger than 0 when the HardSelectionTool is being used
				// if the normal selection tool is used and some shapes are selected the width is 0

				// create a new image with the size of the canvas
				// draw all the shapes in the new image (the whole shape!)
				// crop the new image a the given rectangle

				var dvbase = new DrawingVisual();
				DrawingContext dc = dvbase.RenderOpen();

				foreach (VectorShape shape in copiedShapes)
				{
					shape.Draw(dc);
				}
				dc.Close();

				var renderBitmap = new RenderTargetBitmap(
					(int)canvas.Width,
					(int)canvas.Height,
					96d,
					96d,
					PixelFormats.Pbgra32);

				renderBitmap.Render(dvbase);

				var imconv = new ConvertImageToPbgra32Action();
				BitmapImage image = imconv.ConvertBitmapFormat(renderBitmap);

				var intersection = new Rect(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height);
				intersection.Intersect(new Rect(0, 0, canvas.Width, canvas.Height));

				var rect = new Int32Rect(
					(int)(intersection.X),
					(int)(intersection.Y),
					(int)intersection.Width,
					(int)intersection.Height);

				var cb = new CroppedBitmap(image, rect);

				var mergedImg = new ImageShape(ImageShape.BitmapSourceToImage(cb), intersection.X, intersection.Y);

				var si = new SerializableImage
				{
					Source = mergedImg
				};

				var dataObject = new DataObject();
				//add the serialized image to the dataobject for the clipboard
				dataObject.SetData(si);

				// WHITE BACKGROUND!

				// Create an Image with a white background for other applications.
				// the image has to be white where there should be transparen
				// this has to be done because the clipboard image is only 24bit
				// and can't diplay transparent pixels
				// else all transparent pixels would be drawn in black
				var cddv = new DrawingVisual();
				DrawingContext cbdc = cddv.RenderOpen();

				// clone image so that it can be moved to Point(0,0)
				var img = mergedImg.Clone();
				img.Move(-rectangle.X, -rectangle.Y);
				// draw new image with a white background
				cbdc.DrawRectangle(Brushes.White, new Pen(Brushes.White, 0), new Rect(0, 0, rectangle.Width, rectangle.Height));
				img.Draw(cbdc);
				cbdc.Close();

				var rb2 = new RenderTargetBitmap(
					(int)rectangle.Width,
					(int)rectangle.Height,
					96d,
					96d,
					PixelFormats.Pbgra32);

				rb2.Render(cddv);

				BitmapImage cbimg = imconv.ConvertBitmapFormat(rb2);

				//add the image to the dataobject for the clipboard
				dataObject.SetData(DataFormats.Bitmap, cbimg);

				//copy new rendered image and the serialized image to the clipboard
				Clipboard.SetDataObject(dataObject, false);
			}
			else
			{
				// copy all the selected VectorShapes to the clipboard

				double x = canvas.Width;
				double y = canvas.Height;
				double bottom = 0;
				double right = 0;

				var selection = canvas.SelectedLayer.ShapeList.Selection;

				foreach (VectorShape s in selection)
				{
					if (s.Bounds.X < x)
						x = s.Bounds.X;
					if (s.Bounds.Y < y)
						y = s.Bounds.Y;
					if (s.Bounds.Right > right)
						right = s.Bounds.Right;
					if (s.Bounds.Bottom > bottom)
						bottom = s.Bounds.Bottom;
				}

				var bounds = new Rect(x, y, right - x, bottom - y);

				//offset to new position where upermost image is in position 0,0
				double offx = -bounds.X;
				double offy = -bounds.Y;

				//reposition shapes in a new rectangle
				foreach (var shape in copiedShapes)
				{
					shape.Move(offx, offy);
				}

				// put the shapes in the clipoboard object
				var container = new SerializableShapeContainer();
				foreach (VectorShape shape in copiedShapes)
				{
					container.Push(shape);
				}

				// In case that the selection is to be copied into another program
				// we have to create a image of the selection for pasting into the other program

				// merge all the copied shapes and
				// draw a image from the shapes
				var dvbase = new DrawingVisual();
				DrawingContext dc = dvbase.RenderOpen();

				// WHITE BACKGROUND!
				// Create an Image with a white background for other applications.
				// the image has to be white where there should be transparen
				// this has to be done because the clipboard image is only 24bit
				// and can't diplay transparent pixels
				// else all transparent pixels would be drawn in black

				dc.DrawRectangle(Brushes.White, new Pen(Brushes.White, 0), new Rect(0, 0, bounds.Width, bounds.Height));
				foreach (VectorShape shape in copiedShapes)
				{
					shape.Draw(dc);
				}
				dc.Close();

				// if the bound are 0 then an exception occures when creating the rendertarget (image) for the clipboard
				// the problem is that the thickness of the shape is not accounted for in the image
				// this has to be corrected in the future
				// TODO: The thickness of the schapes at the bounds of the selection have to be added to the bounds when creating an image that is copied to the clipboard
				// recreating the problem:
				//	- create only 1 line where x1 and x2 or y1 and y2 are equal
				//  - select this object an copy it to the clipboard
				if (bounds.Width <= 0)
					bounds.Width = 1;
				if (bounds.Height <= 0)
					bounds.Height = 1;

				// Create a render bitmap and push the surface to it
				var renderBitmap = new RenderTargetBitmap(
					(int) bounds.Width,
					(int) bounds.Height,
					96d,
					96d,
					PixelFormats.Pbgra32);

				renderBitmap.Render(dvbase);

				var imconv = new ConvertImageToPbgra32Action();
				BitmapImage image = imconv.ConvertBitmapFormat(renderBitmap);

				var dataObject = new DataObject();
				// add the serialized shapes to the dataobject for the clipboard
				dataObject.SetData(container);
				// add the image to the dataobject for the clipboard
				dataObject.SetData(DataFormats.Bitmap, image);

				// copy new rendered image and the serialized image to the clipboard
				Clipboard.SetDataObject(dataObject, false);
			}
        }
    }
}
